package com.example.ad.sdk.domain.extensions

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.viewbinding.ViewBinding
import java.lang.reflect.InvocationTargetException
import java.lang.reflect.ParameterizedType

/**
 * 使用泛型方式获取ViewBinding实例。
 *
 * 该函数旨在通过反射获取正确类型的ViewBinding实例。它通过检查类的泛型超类和泛型参数，
 * 找到符合ViewBinding类型的参数，并通过给定的block（函数引用）来创建实例。如果找不到合适的
 * 泛型参数，则会抛出异常。
 *
 * @param aClass 待检查的类，通常是一个Activity或Fragment类
 * @param block 用于创建ViewBinding实例的函数引用
 * @param <V> ViewBinding的类型参数
 * @return 返回通过block创建的ViewBinding实例
 * @throws IllegalArgumentException 如果找不到符合ViewBinding类型的泛型参数，则抛出此异常
 */
internal fun <V : ViewBinding?> withGenericViewBinding(
    aClass: Class<*>, block: (Class<V>) -> V
): V {
    return try {
        // 获取类的泛型超类信息
        val genericSuperclass = aClass.genericSuperclass
        if (genericSuperclass is ParameterizedType) {
            // 遍历泛型参数
            genericSuperclass.actualTypeArguments.forEach {
                val result: Class<*>
                try {
                    // 尝试将泛型参数转换为指定的ViewBinding类型
                    result = it as Class<V>
                } catch (_: Exception) {
                    // 转换失败则终止当前循环
                    return@forEach
                }
                // 检查转换后的类型是否为ViewBinding的子类
                if (ViewBinding::class.java.isAssignableFrom(result)) {
                    // 是则通过block函数创建并返回ViewBinding实例
                    return block.invoke(result)
                }
            }
        }
        // 如果当前类的泛型超类不满足条件，尝试处理其超类
        withGenericViewBinding(aClass.superclass, block)
    } catch (e: Exception) {
        e.printStackTrace()
        throw IllegalArgumentException("There is no generic of ViewBinding.")
    }
}

/**
 * 通过反射获取当前Activity的泛型ViewBinding实例并进行初始化。
 *
 * @param layoutInflater LayoutInflater实例
 * @param <VB> ViewBinding的类型参数
 * @return 初始化后的ViewBinding实例
 */
fun <VB : ViewBinding> AppCompatActivity.inflateBindingWithGeneric(layoutInflater: LayoutInflater): VB =
    viewWithGenericBindingClass(this) {
        it.getMethod("inflate", LayoutInflater::class.java).invoke(null, layoutInflater) as VB
    }

/**
 * 通过反射获取当前Fragment的泛型ViewBinding实例并进行初始化。
 *
 * @param layoutInflater LayoutInflater实例
 * @param parent 父视图组
 * @param attachToParent 是否将视图附加到父视图组
 * @param <VB> ViewBinding的类型参数
 * @return 初始化后的ViewBinding实例
 */
fun <VB : ViewBinding> Fragment.inflateBindingWithGeneric(
    layoutInflater: LayoutInflater,
    parent: ViewGroup?,
    attachToParent: Boolean
): VB = viewWithGenericBindingClass(this) {
    it.getMethod("inflate", LayoutInflater::class.java, ViewGroup::class.java, Boolean::class.java)
        .invoke(null, layoutInflater, parent, attachToParent) as VB
}

/**
 * 通过反射获取泛型ViewBinding类并创建实例。
 *
 * @param any 当前对象，可以是Activity或Fragment
 * @param block 用于创建ViewBinding实例的函数引用
 * @param <VB> ViewBinding的类型参数
 * @return 创建的ViewBinding实例
 * @throws IllegalArgumentException 如果找不到符合ViewBinding类型的泛型参数，则抛出此异常
 */
private fun <VB : ViewBinding> viewWithGenericBindingClass(any: Any, block: (Class<VB>) -> VB): VB {
    var genericSuperclass = any.javaClass.genericSuperclass
    var superclass = any.javaClass.superclass
    while (superclass != null) {
        if (genericSuperclass is ParameterizedType) {
            try {
                return block.invoke(genericSuperclass.actualTypeArguments[0] as Class<VB>)
            } catch (_: NoSuchMethodException) {
            } catch (_: ClassCastException) {
            } catch (e: InvocationTargetException) {
                throw e.targetException
            }
        }
        genericSuperclass = superclass.genericSuperclass
        superclass = superclass.superclass
    }
    throw IllegalArgumentException("There is no generic of ViewBinding.")
}
